#include "GfxDriver/WGL/WGL2DTexture.h"

#include "GfxDriver/WGL/WGLHelper.h"

#include "GfxDriver/GfxDriver.h"
#include "Core/LogService.h"

namespace Orca {

	//--------------------------------------------------------------------------
	WGL2DTexture* WGL2DTexture::create(
		GfxDriver *gfxDriver,
		uint32 w,
		uint32 h,
		PixelFormat format) {

		WGL2DTexture *tex = new WGL2DTexture;

		if( !tex->_init(gfxDriver, w, h, format) ) {

			delete tex;
			return NULL;
		}

		LOG_MSG(
			"WGLGfxDriver: Textrue " + 
			toStr(w) + " x " +
			toStr(h) + "; " +
			"glHandle=" + toStr((uint32)tex->mGLHandle) );

		return tex;
	}

	//--------------------------------------------------------------------------
	bool WGL2DTexture::_init(
		GfxDriver *gfxDriver,
		uint32 w,
		uint32 h,
		PixelFormat format) {

		mGfxDriver = gfxDriver;
		mW = w;
		mH = h;
		mFmt = format;

		mGfxDriver->resetErrors();

		glGenTextures(1, &mGLHandle);

		glBindTexture(GL_TEXTURE_2D, mGLHandle);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

		GLint filterMode = GL_NEAREST;

		switch(mFmt) {

			case PF_INT8_RGBA:
			case PF_INT8_XRGB:
			case PF_INT16_ABGR:
			case PF_INT16_GR:
				filterMode = GL_LINEAR_MIPMAP_LINEAR;
				break;
		}

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterMode);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterMode);

		glBindTexture(GL_TEXTURE_2D, 0);

		return true;
	}

	//--------------------------------------------------------------------------
	WGL2DTexture::WGL2DTexture()
		: mGfxDriver(NULL)
		, mW(0)
		, mH(0)
		, mFmt(PF_UNKNOWN)
		, mData(NULL)
		, mGLHandle(0) {

	}
	
	//--------------------------------------------------------------------------
	WGL2DTexture::~WGL2DTexture() {

		if(mGLHandle)
			glDeleteTextures(1, &mGLHandle);

		if(mData)
			delete[] mData;
	}

	//--------------------------------------------------------------------------
	uint32 WGL2DTexture::getWidth() const {
		return mW;
	}

	//--------------------------------------------------------------------------
	uint32 WGL2DTexture::getHeight() const {
		return mH;
	}

	//--------------------------------------------------------------------------
	PixelFormat WGL2DTexture::getPixelFormat() const {
		return mFmt;
	}

	//--------------------------------------------------------------------------
	void* WGL2DTexture::requestUpload() {

		if(!mData)
			mData = new uint8[mW * mH * WGLHelper::getBytePerPixel(mFmt)];

		return mData;
	}
	
	//--------------------------------------------------------------------------
	bool WGL2DTexture::uploadToGPU(bool autoGenMipmap) {

		glBindTexture( GL_TEXTURE_2D, mGLHandle );
		
		if(autoGenMipmap)
			glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
		else
			glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);

		GLint internalFmt;
		GLenum srcFmt, srcType;
		WGLHelper::getGLPixelFormat(mFmt, internalFmt, srcFmt, srcType);

		glTexImage2D(
			GL_TEXTURE_2D,
			0,
			internalFmt,
			(GLsizei)mW,
			(GLsizei)mH,
			0,
			srcFmt,
			srcType,
			mData);

		GLenum err = glGetError();

		if(err != GL_NO_ERROR) {

			return false;
		}

		delete[] mData;
		mData = NULL;

		glBindTexture( GL_TEXTURE_2D, 0 );

		return true;
	}

	//--------------------------------------------------------------------------
	unsigned int WGL2DTexture::getAPIHandle() const {
		return mGLHandle;
	}

	//--------------------------------------------------------------------------
	unsigned int WGL2DTexture::getAPITexType() const {
		return GL_TEXTURE_2D;
	}

	//--------------------------------------------------------------------------

}